
(in-package :cl-trivial-pool-tests)

(defparameter *test-promise-pool* (tpool:make-thread-pool :name "PROMISE-TEST-POOL"))

(defun gen-0 () 0)

(defun make-promise-promise (final-value &optional (pool tpool:*default-thread-pool*) (name "promised-promise"))
  "Return a promise which will be resolved with another promise"
  (let ((fn (lambda (promise)
              (declare (ignore promise))
              (promise:make-promise
               (lambda (p)
                 (declare (ignore p))
                 final-value)))))
    (promise:make-promise fn :pool pool :name name)))

#+sbcl
(defun kill-pool-threads ()
  "Destroy all thread of the pool (thread name starts with 'WORKER-OF-')."
  (dolist (thread (bt:all-threads))
    (when (string= "WORKER-OF-" (subseq (sb-thread:thread-name thread) 0 10))
      (ignore-errors (bt:destroy-thread thread)))))

(defun basic-promise-gen (type)
  "Generate 6 basic promises which resolve/reject with non-promise objects,
valid `type':
:empty, return an empty promise, can be used to test attach, but do not send it to a thread pool.
:simple, no resolve invoked, no rejecte invoked, no error signaled, degenerated to a normal work-item.
:simpke-err, no resolve invoked, no rejecte invoked, error signaled, will be rejected automatically.
:explicit-resolve, resolved by invoking resolve.
:reject-err, rejected by calling resolve with an error.
:reject-non-err, rejected by calling resolve with non-error data.
"
  (ecase type
    (:empty (promise:make-empty-promise *test-promise-pool* "empty-promise-only-name-and-pool-spicified"))
    (:simple (promise:make-promise (lambda (promise)
                                     (declare (ignore promise)) (+ 1 2 3))
                                   :pool *test-promise-pool* :name "simple-promise"))
    (:simple-err (promise:make-promise (lambda (promise)
                                         (declare (ignore promise))
                                         (let* ((x (gen-0))
                                                (y (/ 1 x)))
                                           (format t "Printing this showed a bug, :simple-err promise!~%")
                                           y))
                                       :pool *test-promise-pool* :name "simple-error-promise"))
    (:explicit-resolve (promise:make-promise (lambda (promise)
                                               (let ((result (+ 1 2 3)))
                                                 (promise:resolve promise result)
                                                 ;;(promise:signal-promise-resolving result)
                                                 (format t "Printing this showed a bug, :explicit-resolve promise!~%")
                                                 result))
                                             :pool *test-promise-pool* :name "explicit-resolve"))
    (:reject-err (promise:make-promise (lambda (promise)
                                         (promise:reject promise (promise:make-promise-error 123 "xx"))
                                         (format t "Printing this showed a bug, :reject-err promise!~%"))
                                       :pool *test-promise-pool* :name "explicit-reject-promise-err"))
    (:reject-non-err (promise:make-promise (lambda (promise)
                                             (promise:reject promise 123)
                                             (format t "Printing this showed a bug, :reject-non-err promise!~%"))
                                           :pool *test-promise-pool* :name "reject-with-ordinary-data"))))

(defun promised-promise-gen (type)
  "combination of several basic promises above: simple, simple-err, explicit-resolve,
as well as reject with another promise.
return a promise that will be fulfilled with another promise.
:simple-err is not applicable here since it's rejected with error signaled."
  (ecase type
    ;; simple | simple, simple-err, explicit-resolve, reject-err, reject-non-err
    (:simple/simple (promise:make-promise (lambda (promise)
                                            (declare (ignore promise))
                                            (basic-promise-gen :simple))
                                          :pool *test-promise-pool* :name "simple/simple"))
    (:simple/simple-err (promise:make-promise (lambda (promise)
                                                (declare (ignore promise))
                                                (basic-promise-gen :simple-err))
                                              :pool *test-promise-pool* :name "simple/simple-err"))
    (:simple/explicit-resolve (promise:make-promise (lambda (promise)
                                                      (declare (ignore promise))
                                                      (basic-promise-gen :explicit-resolve))
                                                    :pool *test-promise-pool* :name "simple/explicit-resolve"))
    (:simple/reject-err (promise:make-promise (lambda (promise)
                                                (declare (ignore promise))
                                                (basic-promise-gen :reject-err))
                                              :pool *test-promise-pool* :name "simple/reject-err"))
    (:simple/reject-non-err (promise:make-promise (lambda (promise)
                                                    (declare (ignore promise))
                                                    (basic-promise-gen :reject-non-err))
                                                  :pool *test-promise-pool* :name "simple/reject-non-err"))
    ;; explicit-resolve | simple, simple-err, explicit-resolve, reject-err, reject-non-err
    (:explicit-resolve/simple
     (promise:make-promise (lambda (promise)
                             (let ((result (basic-promise-gen :simple)))
                               (promise:resolve promise result)
                               ;;(promise:signal-promise-resolving result)
                               (format t "Printing this showed a bug, :explicit-resolve/simple promise!~%")
                               result))
                           :pool *test-promise-pool* :name "explicit-resolve/simple"))
    (:explicit-resolve/simple-err
     (promise:make-promise (lambda (promise)
                             (let ((result (basic-promise-gen :simple-err)))
                               (promise:resolve promise result)
                               ;;(promise:signal-promise-resolving result)
                               (format t "Printing this showed a bug, :explicit-resolve/simple-err promise!~%")
                               result))
                           :pool *test-promise-pool* :name "explicit-resolve/simple-err"))
    (:explicit-resolve/explicit-resolve
     (promise:make-promise (lambda (promise)
                             (let ((result (basic-promise-gen :explicit-resolve)))
                               (promise:resolve promise result)
                               ;;(promise:signal-promise-resolving result)
                               (format t "Printing this showed a bug, :explicit-resolve/explicit-resolve promise!~%")
                               result))
                           :pool *test-promise-pool* :name "explicit-resolve/explicit-resolve"))
    (:explicit-resolve/reject-err
     (promise:make-promise (lambda (promise)
                             (let ((result (basic-promise-gen :reject-err)))
                               (promise:resolve promise result)
                               ;;(promise:signal-promise-resolving result)
                               (format t "Printing this showed a bug, :explicit-resolve/reject-err promise!~%")
                               result))
                           :pool *test-promise-pool* :name "explicit-resolve/reject-err"))
    (:explicit-resolve/reject-non-err
     (promise:make-promise (lambda (promise)
                             (let ((result (basic-promise-gen :reject-non-err)))
                               (promise:resolve promise result)
                               ;;(promise:signal-promise-resolving result)
                               (format t "Printing this showed a bug, :explicit-resolve/reject-non-err promise!~%")
                               result))
                           :pool *test-promise-pool* :name "explicit-resolve/reject-non-err"))
    ;; reject | simple, simple-err, explicit-resolve, reject-err, reject-non-err
    (:reject/simple (promise:make-promise (lambda (promise)
                                            (promise:reject promise (basic-promise-gen :simple))
                                            (format t "Printing this showed a bug, :reject/simple promise!~%"))
                                          :pool *test-promise-pool* :name "reject/simple"))
    (:reject/simple-err (promise:make-promise (lambda (promise)
                                                (promise:reject promise (basic-promise-gen :simple-err))
                                                (format t "Printing this showed a bug, :reject/simple-err promise!~%"))
                                              :pool *test-promise-pool* :name "reject/simple-err"))
    (:reject/explicit-resolve (promise:make-promise (lambda (promise)
                                                      (promise:reject promise (basic-promise-gen :explicit-resolve))
                                                      (format t "Printing this showed a bug, :reject/explicit-resolve promise!~%"))
                                                    :pool *test-promise-pool* :name "reject/explicit-resolve"))
    (:reject/reject-err (promise:make-promise (lambda (promise)
                                                (promise:reject promise (basic-promise-gen :reject-err))
                                                (format t "Printing this showed a bug, :reject/reject-err promise!~%"))
                                              :pool *test-promise-pool* :name "reject/reject-err"))
    (:reject/reject-non-err (promise:make-promise (lambda (promise)
                                                    (promise:reject promise (basic-promise-gen :reject-non-err))
                                                    (format t "Printing this showed a bug, :reject/reject-non-err promise!~%"))
                                                  :pool *test-promise-pool* :name "reject/reject-non-err"))))

(defun nested-promise-gen (depth type &optional current-promise)
  "Return a promise that will be fulfilled with another promise that will be fulfilled with another promise ...
with `depth' depth, and the last promise is of type `type' showed above."
  (if (< depth 0)
      current-promise
      (if (null current-promise)
          (let ((new-promise (basic-promise-gen type))
                (callback-fn (lambda (pms &rest args)
                               (declare (ignore pms))
                               (format t "~&....Call back for promise ~d with args <~d>.~%" depth args)))
                (errback-fn  (lambda (pms err)
                               (declare (ignore pms))
                               (format t "~&....Error back for promise ~d with err <~d>.~%" depth err))))
            (promise:attach-echoback new-promise current-promise callback-fn errback-fn)
            (nested-promise-gen (1- depth) type new-promise))
          (let ((new-promise (promise:make-promise (lambda (pms)
                                                     (declare (ignore pms))
                                                     current-promise)
                                                   :pool *test-promise-pool*
                                                   :name (format nil "NESTED-PROMISE-~d" depth)))
                (callback-fn (lambda (pms &rest args)
                               (declare (ignore pms))
                               (format t "~&....Call back for promise ~d with args <~d>.~%" depth args)))
                (errback-fn  (lambda (pms err)
                               (declare (ignore pms))
                               (format t "~&....Error back for promise ~d with err <~d>.~%" depth err))))
            (promise:attach-echoback new-promise current-promise callback-fn errback-fn)
            (nested-promise-gen (1- depth) type new-promise)))))



;;; -------

(define-test make-promise-condition :parent promise
  (let* ((reason "some-reason")
         (data 123456)
         (condition (promise:make-promise-condition data))
         (warning   (promise:make-promise-warning data reason))
         (err       (promise:make-promise-error data reason))
         (resolving (promise:make-promise-resolve-condition data)))
    (of-type promise:promise-condition condition)
    (of-type promise:promise-warning   warning)
    (of-type promise:promise-error     err)
    (of-type promise:promise-resolve-condition resolving)
    ;;(is equal reason (slot-value condition 'promise::reason))
    (is equal data   (slot-value condition 'promise::data))
    (is equal reason (slot-value warning 'promise::reason))
    (is equal data   (slot-value warning 'promise::data))
    (is equal reason (slot-value err 'promise::reason))
    (is equal data   (slot-value err 'promise::data))
    (is equal data   (slot-value resolving 'promise::data))))

(define-test signal-promise-condition :parent promise
  (fail (promise:signal-promise-error 123 "xxx"))
  (finish (promise:signal-promise-warning 123 "xxx"))
  (finish (promise:signal-promise-condition 123))
  (finish (promise:signal-promise-resolving 123)))

(define-test inspect-promise :parent promise
  (finish (promise:inspect-promise (make-instance 'promise:promise))))

(define-test promisep :parent promise
  (let ((promise (make-instance 'promise:promise))
        (work (tpool:make-work-item)))
    #+sbcl(is-values (promise:promisep promise) (eq t) (eq t))
    #-sbcl(is eql t (promise:promisep promise))

    #+sbcl(is-values (promise:promisep work) (eq nil) (eq t))
    #-sbcl(is eql nil (promise:promisep work))

    #+sbcl(is-values (tpool:work-item-p promise) (eq t) (eq t))
    #-sbcl(is eql t (tpool:work-item-p work))

    #+sbcl(is-values (tpool:work-item-p work) (eq t) (eq t))
    #-sbcl(is eql t (tpool:work-item-p work))))

(define-test make-empty-promise :parent promise
  (true (promise:promisep (promise:make-empty-promise))))

(define-test make-promise :parent promise
  (let* ((pool (tpool:make-thread-pool))
         ;; simple-promise degenerates to a normal work-item, so it will neither be resolved nor finished.
         (simple-promise (promise:make-promise (lambda (promise) (declare (ignore promise)) (+ 1 2 3)) :pool pool))
         ;; simple-err-promise degenerates to a normal work-item, but the error will be handled and rejected with that.
         (simple-err-promise (promise:make-promise (lambda (promise)
                                                     (declare (ignore promise))
                                                     (let* ((x (gen-0))
                                                            (y (/ 1 x)))
                                                       (format t "This cannot be reached, or there must be a bug!~%")
                                                       y))
                                                   :pool pool))
         ;; explicit resolve invoking
         (resolvable-promise (promise:make-promise (lambda (promise)
                                                     (let ((result (+ 1 2 3)))
                                                       (promise:resolve promise result)
                                                       (promise:signal-promise-resolving result)
                                                       (format t "This should not be reached, or there must be a bug!~%")
                                                       result))
                                                   :pool pool))
         ;; error signaled by promise:signal-promise-error, this is also a degenerated normal work-item
         (rejectable-promise-1 (promise:make-promise (lambda (promise)
                                                       (declare (ignore promise))
                                                       (promise:signal-promise-error 123 "test error promise")
                                                       (format t "This cannot be reached, or there must be a bug!~%"))
                                                     :pool pool))
         ;; explicit reject invoking, reject with an promise-error
         (rejectable-promise-2 (promise:make-promise (lambda (promise)
                                                       (promise:reject promise (promise:make-promise-error 123 "xx"))
                                                       (format t "This cannot be reached, or there must be a bug!~%"))
                                                     :pool pool))
         ;; explicit reject invoking, reject with a normal error
         (rejectable-promise-3 (promise:make-promise (lambda (promise)
                                                       (promise:reject promise (make-instance 'error))
                                                       (format t "This cannot be reached, or there must be a bug!~%"))
                                                     :pool pool))
         ;; explicit reject invoking, reject with an ordinary data
         (rejectable-promise-4 (promise:make-promise (lambda (promise)
                                                       (promise:reject promise 123)
                                                       (format t "This cannot be reached, or there must be a bug!~%"))
                                                     :pool pool)))
    (finish (tpool:add-work simple-promise))
    (finish (tpool:add-work simple-err-promise))
    (finish (tpool:add-work resolvable-promise))
    (finish (tpool:add-work rejectable-promise-1))
    (finish (tpool:add-work rejectable-promise-2))
    (finish (tpool:add-work rejectable-promise-3))
    (finish (tpool:add-work rejectable-promise-4))
    (sleep 0.0001)
    ;; degenerated promise
    (is-values (tpool:get-result simple-promise) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status simple-promise))
    (is eq t   (promise:promise-finished-p simple-promise))
    (is eq t   (promise:promise-resolved-p simple-promise))
    (is eq nil (promise:promise-rejected-p simple-promise))
    (is eq nil (promise:promise-errored-p  simple-promise))
    (is eq nil (promise:promise-error-obj  simple-promise))
    ;; degenerated promise with error signaled
    (is-values (tpool:get-result simple-err-promise) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result simple-err-promise)))
    (is eq :errored (tpool:get-status simple-err-promise))
    (is eq nil (promise:promise-finished-p simple-err-promise))
    (is eq nil (promise:promise-resolved-p simple-err-promise))
    (is eq t   (promise:promise-rejected-p simple-err-promise))
    (is eq t   (promise:promise-errored-p  simple-err-promise))
    (of-type error (promise:promise-error-obj simple-err-promise))
    ;; resolvable promise
    ;; ----------------- have bugs now --------------------
    (is-values (tpool:get-result resolvable-promise) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status resolvable-promise))
    (is eq t   (promise:promise-finished-p resolvable-promise)) ; finished and resolved
    (is eq t   (promise:promise-resolved-p resolvable-promise))
    (is eq nil (promise:promise-rejected-p resolvable-promise))
    (is eq nil (promise:promise-errored-p  resolvable-promise))
    (is eq nil (promise:promise-error-obj  resolvable-promise))
    ;; rejectable promise, error signaled with promise:signal-promise-error, also a degenerated normal work-item
    (is-values (tpool:get-result rejectable-promise-1) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-1)))
    (is eq :errored (tpool:get-status rejectable-promise-1))
    (is eq nil (promise:promise-finished-p rejectable-promise-1))
    (is eq nil (promise:promise-resolved-p rejectable-promise-1))
    (is eq t   (promise:promise-rejected-p rejectable-promise-1))
    (is eq t   (promise:promise-errored-p  rejectable-promise-1))
    (of-type error (promise:promise-error-obj rejectable-promise-1))
    ;; explicit reject invoking, reject with an promise-error
    (is-values (tpool:get-result rejectable-promise-2) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-2)))
    (is eq :errored (tpool:get-status rejectable-promise-2))
    (is eq nil (promise:promise-finished-p rejectable-promise-2))
    (is eq nil (promise:promise-resolved-p rejectable-promise-2))
    (is eq t   (promise:promise-rejected-p rejectable-promise-2))
    (is eq t   (promise:promise-errored-p  rejectable-promise-2))
    (of-type error (promise:promise-error-obj rejectable-promise-2))
    ;; explicit reject invoking, reject with a normal error
    (is-values (tpool:get-result rejectable-promise-3) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-3)))
    (is eq :errored (tpool:get-status rejectable-promise-3))
    (is eq nil (promise:promise-finished-p rejectable-promise-3))
    (is eq nil (promise:promise-resolved-p rejectable-promise-3))
    (is eq t   (promise:promise-rejected-p rejectable-promise-3))
    (is eq t   (promise:promise-errored-p  rejectable-promise-3))
    (of-type error (promise:promise-error-obj rejectable-promise-3))
    ;; explicit reject invoking, reject with an ordinary data
    (is-values (tpool:get-result rejectable-promise-4) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-4)))
    (is eq :errored (tpool:get-status rejectable-promise-4))
    (is eq nil (promise:promise-finished-p rejectable-promise-4))
    (is eq nil (promise:promise-resolved-p rejectable-promise-4))
    (is eq t   (promise:promise-rejected-p rejectable-promise-4))
    (is eq t   (promise:promise-errored-p  rejectable-promise-4))
    (of-type error (promise:promise-error-obj rejectable-promise-4))
    ))

(define-test with-promise :parent promise
  (let* ((pool (tpool:make-thread-pool))
         ;; simple-promise degenerates to a normal work-item, so it will neither be resolved nor finished.
         (simple-promise (promise:with-promise (promise :pool pool) (+ 1 2 3)))
         ;; degenerated promise, with bindings specified
         (simple-promise-with-bindings (promise:with-promise (promise :bindings '((a 1) (b 2) (c 3)) :pool pool)
                                         (+ a b c)))
         ;; simple-err-promise degenerates to a normal work-item, but the error will be handled and rejected with that.
         (simple-err-promise (promise:with-promise (promise :pool pool :name "simple-err-promise")
                               (let* ((x (gen-0))
                                      (y (/ 1 x)))
                                 (format t "This cannot be reached, or there must be a bug!~%")
                                 y)))
         ;; explicit resolve invoking
         (resolvable-promise (promise:with-promise (promise :pool pool)
                               (let ((result (+ 1 2 3)))
                                 (promise:resolve promise result)
                                 (promise:signal-promise-resolving result)
                                 (format t "This should not be reached, or there must be a bug!~%")
                                 result)))
         ;; error signaled by promise:signal-promise-error, this is also a degenerated normal work-item
         (rejectable-promise-1 (promise:with-promise (promise :pool pool)
                                 (promise:signal-promise-error 123 "test error promise")
                                 (format t "This cannot be reached, or there must be a bug!~%")))
         ;; explicit reject invoking, reject with an promise-error
         (rejectable-promise-2 (promise:with-promise (promise :pool pool)
                                 (promise:reject promise (promise:make-promise-error 123 "xx"))
                                 (format t "This cannot be reached, or there must be a bug!~%")))
         ;; explicit reject invoking, reject with a normal error
         (rejectable-promise-3 (promise:with-promise (promise :pool pool)
                                 (promise:reject promise (make-instance 'error))
                                 (format t "This cannot be reached, or there must be a bug!~%")))
         ;; explicit reject invoking, reject with an ordinary data
         (rejectable-promise-4 (promise:with-promise (promise :pool pool)
                                 (promise:reject promise 123)
                                 (format t "This cannot be reached, or there must be a bug!~%"))))
    (finish (tpool:add-work simple-promise))
    (finish (tpool:add-work simple-promise-with-bindings))
    (finish (tpool:add-work simple-err-promise))
    (finish (tpool:add-work resolvable-promise))
    (finish (tpool:add-work rejectable-promise-1))
    (finish (tpool:add-work rejectable-promise-2))
    (finish (tpool:add-work rejectable-promise-3))
    (finish (tpool:add-work rejectable-promise-4))
    (sleep 0.0001)

    ;; degenerated promise
    (is-values (tpool:get-result simple-promise) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status simple-promise))
    (is eq t   (promise:promise-finished-p simple-promise))
    (is eq t   (promise:promise-resolved-p simple-promise))
    (is eq nil (promise:promise-rejected-p simple-promise))
    (is eq nil (promise:promise-errored-p  simple-promise))
    (is eq nil (promise:promise-error-obj  simple-promise))
    ;; degenerated promise with bindings
    (is-values (tpool:get-result simple-promise-with-bindings) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status simple-promise-with-bindings))
    (is eq t   (promise:promise-finished-p simple-promise-with-bindings))
    (is eq t   (promise:promise-resolved-p simple-promise-with-bindings))
    (is eq nil (promise:promise-rejected-p simple-promise-with-bindings))
    (is eq nil (promise:promise-errored-p  simple-promise-with-bindings))
    (is eq nil (promise:promise-error-obj  simple-promise-with-bindings))
    ;; degenerated promise with error signaled
    (is-values (tpool:get-result simple-err-promise) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result simple-err-promise)))
    (is eq :errored (tpool:get-status simple-err-promise))
    (is eq nil (promise:promise-finished-p simple-err-promise))
    (is eq nil (promise:promise-resolved-p simple-err-promise))
    (is eq t   (promise:promise-rejected-p simple-err-promise))
    (is eq t   (promise:promise-errored-p  simple-err-promise))
    (of-type error (promise:promise-error-obj simple-err-promise))
    ;; resolvable promise
    (is-values (tpool:get-result resolvable-promise) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status resolvable-promise))
    (is eq t   (promise:promise-finished-p resolvable-promise)) ; finished and resolved
    (is eq t   (promise:promise-resolved-p resolvable-promise))
    (is eq nil (promise:promise-rejected-p resolvable-promise))
    (is eq nil (promise:promise-errored-p  resolvable-promise))
    (is eq nil (promise:promise-error-obj  resolvable-promise))
    ;; rejectable promise, error signaled with promise:signal-promise-error, also a degenerated normal work-item
    (is-values (tpool:get-result rejectable-promise-1) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-1)))
    (is eq :errored (tpool:get-status rejectable-promise-1))
    (is eq nil (promise:promise-finished-p rejectable-promise-1))
    (is eq nil (promise:promise-resolved-p rejectable-promise-1))
    (is eq t   (promise:promise-rejected-p rejectable-promise-1))
    (is eq t   (promise:promise-errored-p  rejectable-promise-1))
    (of-type error (promise:promise-error-obj rejectable-promise-1))
    ;; explicit reject invoking, reject with an promise-error
    (is-values (tpool:get-result rejectable-promise-2) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-2)))
    (is eq :errored (tpool:get-status rejectable-promise-2))
    (is eq nil (promise:promise-finished-p rejectable-promise-2))
    (is eq nil (promise:promise-resolved-p rejectable-promise-2))
    (is eq t   (promise:promise-rejected-p rejectable-promise-2))
    (is eq t   (promise:promise-errored-p  rejectable-promise-2))
    (of-type error (promise:promise-error-obj rejectable-promise-2))
    ;; explicit reject invoking, reject with a normal error
    (is-values (tpool:get-result rejectable-promise-3) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-3)))
    (is eq :errored (tpool:get-status rejectable-promise-3))
    (is eq nil (promise:promise-finished-p rejectable-promise-3))
    (is eq nil (promise:promise-resolved-p rejectable-promise-3))
    (is eq t   (promise:promise-rejected-p rejectable-promise-3))
    (is eq t   (promise:promise-errored-p  rejectable-promise-3))
    (of-type error (promise:promise-error-obj rejectable-promise-3))
    ;; explicit reject invoking, reject with an ordinary data
    (is-values (tpool:get-result rejectable-promise-4) (eq nil) (eq nil))
    (of-type error (car (tpool:work-item-result rejectable-promise-4)))
    (is eq :errored (tpool:get-status rejectable-promise-4))
    (is eq nil (promise:promise-finished-p rejectable-promise-4))
    (is eq nil (promise:promise-resolved-p rejectable-promise-4))
    (is eq t   (promise:promise-rejected-p rejectable-promise-4))
    (is eq t   (promise:promise-errored-p  rejectable-promise-4))
    (of-type error (promise:promise-error-obj rejectable-promise-4))
    ))

(define-test attach :parent promise
  (let* ((pool (tpool:make-thread-pool))
         (simple-promise (promise:make-promise (lambda (promise)
                                                 (declare (ignore promise)) (+ 1 2 3))
                                               :pool pool :name "simple-promise"))
         ;; simple-err-promise degenerates to a normal work-item, but the error will be handled and rejected with that.
         (simple-err-promise (promise:make-promise (lambda (promise)
                                                     (declare (ignore promise))
                                                     (let* ((x (gen-0))
                                                            (y (/ 1 x)))
                                                       (format t "This cannot be reached, or there must be a bug!~%")
                                                       y))
                                                   :pool pool :name "simple-err-promise"))
         ;; explicit resolve invoking
         (resolvable-promise (promise:make-promise (lambda (promise)
                                                     (let ((result (+ 1 2 3)))
                                                       (promise:resolve promise result)
                                                       (promise:signal-promise-resolving result)
                                                       (format t "This should not be reached, or there must be a bug!~%")
                                                       result))
                                                   :pool pool :name "explicit-resolve"))
         ;; resolvable-promise-1, error signaled by promise:signal-promise-error, this is also a degenerated normal work-item,
         ;;   thus it's not included here
         ;; explicit reject invoking, reject with an promise-error
         (rejectable-promise-2 (promise:make-promise (lambda (promise)
                                                       (promise:reject promise (promise:make-promise-error 123 "xx"))
                                                       (format t "This cannot be reached, or there must be a bug!~%"))
                                                     :pool pool :name "explicit-reject-promise-err"))
         ;; explicit reject invoking, reject with a normal error
         (rejectable-promise-3 (promise:make-promise (lambda (promise)
                                                       (promise:reject promise (make-instance 'error))
                                                       (format t "This cannot be reached, or there must be a bug!~%"))
                                                     :pool pool :name "explicit-reject-normal-err"))
         ;; explicit reject invoking, reject with an ordinary data
         (rejectable-promise-4 (promise:make-promise (lambda (promise)
                                                       (promise:reject promise 123)
                                                       (format t "This cannot be reached, or there must be a bug!~%"))
                                                     :pool pool :name "reject-with-ordinary-data"))
         )
    (let ((this-promise simple-promise)
          (echo-1 (promise:make-empty-promise))
          (echo-2 (promise:make-empty-promise))
          (echo-3 (promise:make-empty-promise))
          (callback-fn (lambda (p &rest values) (apply #'promise:resolve p values)))
          (errback-fn (lambda (p err) (promise:reject p err))))
      (finish (promise:attach-echoback this-promise echo-1 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-2 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-3 callback-fn errback-fn))
      (tpool:add-work this-promise)
      (sleep 0.01)
      (is eq :finished (tpool:get-status this-promise))
      (is-values (tpool:get-result this-promise) (equal (list 6)) (eq t))
      (is eq t   (promise:promise-resolved-p this-promise))
      (is eq t   (promise:promise-resolved-p echo-1))
      (is eq t   (promise:promise-resolved-p echo-2))
      (is eq t   (promise:promise-resolved-p echo-3))
      (is eq nil (promise:promise-rejected-p this-promise))
      (is eq nil (promise:promise-rejected-p echo-1))
      (is eq nil (promise:promise-rejected-p echo-2))
      (is eq nil (promise:promise-rejected-p echo-3))
      ;;(format t "~%~%this-promise: ~d~%" this-promise)
      ;;(format t "~%echo-promise-1: ~d~%" echo-1)
      ;;(format t "~%echo-promise-2: ~d~%" echo-2)
      ;;(format t "~%echo-promise-3: ~d~%~%" echo-3)
      )
    (let ((this-promise simple-err-promise)
          (echo-1 (promise:make-empty-promise))
          (echo-2 (promise:make-empty-promise))
          (echo-3 (promise:make-empty-promise))
          (callback-fn (lambda (p &rest values) (apply #'promise:resolve p values)))
          (errback-fn (lambda (p err) (promise:reject p err))))
      (finish (promise:attach-echoback this-promise echo-1 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-2 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-3 callback-fn errback-fn))
      (tpool:add-work this-promise)
      (sleep 0.01)
      (is eq :errored (tpool:get-status this-promise))
      (is-values (tpool:get-result this-promise) (eql nil) (eq nil))
      (is eq nil (promise:promise-resolved-p this-promise))
      (is eq nil (promise:promise-resolved-p echo-1))
      (is eq nil (promise:promise-resolved-p echo-2))
      (is eq nil (promise:promise-resolved-p echo-3))
      (is eq t   (promise:promise-rejected-p this-promise))
      (is eq t   (promise:promise-rejected-p echo-1))
      (is eq t   (promise:promise-rejected-p echo-2))
      (is eq t   (promise:promise-rejected-p echo-3))
      ;;(format t "~%~%this-promise: ~d~%" this-promise)
      ;;(format t "~%echo-promise-1: ~d~%" echo-1)
      ;;(format t "~%echo-promise-2: ~d~%" echo-2)
      ;;(format t "~%echo-promise-3: ~d~%~%" echo-3)
      )
    (let ((this-promise resolvable-promise)
          (echo-1 (promise:make-empty-promise pool "echo1"))
          (echo-2 (promise:make-empty-promise pool "echo2"))
          (echo-3 (promise:make-empty-promise pool "echo3"))
          (callback-fn (lambda (p &rest values) (apply #'promise:resolve p values)))
          (errback-fn (lambda (p err) (promise:reject p err))))
      (finish (promise:attach-echoback this-promise echo-1 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-2 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-3 callback-fn errback-fn))
      (tpool:add-work this-promise)
      (sleep 0.01)
      (is eq :finished (tpool:get-status this-promise))
      (is-values (tpool:get-result this-promise nil) (equal (list 6)) (eq t))
      (is eq t   (promise:promise-resolved-p this-promise))
      (is eq t   (promise:promise-resolved-p echo-1))
      (is eq t   (promise:promise-resolved-p echo-2))
      (is eq t   (promise:promise-resolved-p echo-3))
      (is eq nil (promise:promise-rejected-p this-promise))
      (is eq nil (promise:promise-rejected-p echo-1))
      (is eq nil (promise:promise-rejected-p echo-2))
      (is eq nil (promise:promise-rejected-p echo-3))
      ;;(format t "~%~%this-promise: ~d~%" this-promise)
      ;;(format t "~%echo-promise-1: ~d~%" echo-1)
      ;;(format t "~%echo-promise-2: ~d~%" echo-2)
      ;;(format t "~%echo-promise-3: ~d~%~%" echo-3)
      )
    (let ((this-promise rejectable-promise-2)
          (echo-1 (promise:make-empty-promise))
          (echo-2 (promise:make-empty-promise))
          (echo-3 (promise:make-empty-promise))
          (callback-fn (lambda (p &rest values) (apply #'promise:resolve p values)))
          (errback-fn (lambda (p err) (promise:reject p err))))
      (finish (promise:attach-echoback this-promise echo-1 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-2 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-3 callback-fn errback-fn))
      (tpool:add-work this-promise)
      (sleep 0.01)
      (is eq :errored (tpool:get-status this-promise))
      (is-values (tpool:get-result this-promise nil) (eq nil) (eq nil))
      (is eq nil (promise:promise-resolved-p this-promise))
      (is eq nil (promise:promise-resolved-p echo-1))
      (is eq nil (promise:promise-resolved-p echo-2))
      (is eq nil (promise:promise-resolved-p echo-3))
      (is eq t   (promise:promise-rejected-p this-promise))
      (is eq t   (promise:promise-rejected-p echo-1))
      (is eq t   (promise:promise-rejected-p echo-2))
      (is eq t   (promise:promise-rejected-p echo-3))
      ;;(format t "~%~%this-promise: ~d~%" this-promise)
      ;;(format t "~%echo-promise-1: ~d~%" echo-1)
      ;;(format t "~%echo-promise-2: ~d~%" echo-2)
      ;;(format t "~%echo-promise-3: ~d~%~%" echo-3)
      )
    (let ((this-promise rejectable-promise-3)
          (echo-1 (promise:make-empty-promise))
          (echo-2 (promise:make-empty-promise))
          (echo-3 (promise:make-empty-promise))
          (callback-fn (lambda (p &rest values) (apply #'promise:resolve p values)))
          (errback-fn (lambda (p err) (promise:reject p err))))
      (finish (promise:attach-echoback this-promise echo-1 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-2 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-3 callback-fn errback-fn))
      (tpool:add-work this-promise)
      (sleep 0.01)
      (is eq :errored (tpool:get-status this-promise))
      (is-values (tpool:get-result this-promise nil) (eq nil) (eq nil))
      (is eq nil (promise:promise-resolved-p this-promise))
      (is eq nil (promise:promise-resolved-p echo-1))
      (is eq nil (promise:promise-resolved-p echo-2))
      (is eq nil (promise:promise-resolved-p echo-3))
      (is eq t   (promise:promise-rejected-p this-promise))
      (is eq t   (promise:promise-rejected-p echo-1))
      (is eq t   (promise:promise-rejected-p echo-2))
      (is eq t   (promise:promise-rejected-p echo-3))
      ;;(format t "~%~%this-promise: ~d~%" this-promise)
      ;;(format t "~%echo-promise-1: ~d~%" echo-1)
      ;;(format t "~%echo-promise-2: ~d~%" echo-2)
      ;;(format t "~%echo-promise-3: ~d~%~%" echo-3)
      )
    (let ((this-promise rejectable-promise-4)
          (echo-1 (promise:make-empty-promise))
          (echo-2 (promise:make-empty-promise))
          (echo-3 (promise:make-empty-promise))
          (callback-fn (lambda (p &rest values) (apply #'promise:resolve p values)))
          (errback-fn (lambda (p err) (promise:reject p err))))
      (finish (promise:attach-echoback this-promise echo-1 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-2 callback-fn errback-fn))
      (finish (promise:attach-echoback this-promise echo-3 callback-fn errback-fn))
      (tpool:add-work this-promise)
      (sleep 0.01)
      (is eq :errored (tpool:get-status this-promise))
      (is-values (tpool:get-result this-promise nil) (eq nil) (eq nil))
      (is eq nil (promise:promise-resolved-p this-promise))
      (is eq nil (promise:promise-resolved-p echo-1))
      (is eq nil (promise:promise-resolved-p echo-2))
      (is eq nil (promise:promise-resolved-p echo-3))
      (is eq t   (promise:promise-rejected-p this-promise))
      (is eq t   (promise:promise-rejected-p echo-1))
      (is eq t   (promise:promise-rejected-p echo-2))
      (is eq t   (promise:promise-rejected-p echo-3))
      ;;(format t "~%~%this-promise: ~d~%" this-promise)
      ;;(format t "~%echo-promise-1: ~d~%" echo-1)
      ;;(format t "~%echo-promise-2: ~d~%" echo-2)
      ;;(format t "~%echo-promise-3: ~d~%~%" echo-3)
      )))

(define-test forward :parent promise
  ;; subset of the combinations of simple, simple-err, explicit-resolve, reject-err, reject-non-err
  (let* ((simple/simple           (promised-promise-gen :simple/simple))
         (simple/simple-err       (promised-promise-gen :simple/simple-err))
         (simple/explicit-resolve (promised-promise-gen :simple/explicit-resolve))
         (simple/reject-err       (promised-promise-gen :simple/reject-err))
         (simple/reject-non-err   (promised-promise-gen :simple/reject-non-err))

         (explicit-resolve/simple           (promised-promise-gen :explicit-resolve/simple))
         (explicit-resolve/simple-err       (promised-promise-gen :explicit-resolve/simple-err))
         (explicit-resolve/explicit-resolve (promised-promise-gen :explicit-resolve/explicit-resolve))
         (explicit-resolve/reject-err       (promised-promise-gen :explicit-resolve/reject-err))
         (explicit-resolve/reject-non-err   (promised-promise-gen :explicit-resolve/reject-non-err))

         (reject/simple           (promised-promise-gen :reject/simple))
         (reject/simple-err       (promised-promise-gen :reject/simple-err))
         (reject/explicit-resolve (promised-promise-gen :reject/explicit-resolve))
         (reject/reject-err       (promised-promise-gen :reject/reject-err))
         (reject/reject-non-err   (promised-promise-gen :reject/reject-non-err)))

    (true (promise:promisep simple/simple))
    (true (promise:promisep simple/simple-err))
    (true (promise:promisep simple/explicit-resolve))
    (true (promise:promisep simple/reject-err))
    (true (promise:promisep simple/reject-non-err))

    (true (promise:promisep explicit-resolve/simple))
    (true (promise:promisep explicit-resolve/simple-err))
    (true (promise:promisep explicit-resolve/explicit-resolve))
    (true (promise:promisep explicit-resolve/reject-err))
    (true (promise:promisep explicit-resolve/reject-non-err))

    (true (promise:promisep reject/simple))
    (true (promise:promisep reject/simple-err))
    (true (promise:promisep reject/explicit-resolve))
    (true (promise:promisep reject/reject-err))
    (true (promise:promisep reject/reject-non-err))

    (finish (promise:add-work simple/simple))
    (finish (promise:add-work simple/simple-err))
    (finish (promise:add-work simple/explicit-resolve))
    (finish (promise:add-work simple/reject-err))
    (finish (promise:add-work simple/reject-non-err))

    (finish (promise:add-work explicit-resolve/simple))
    (finish (promise:add-work explicit-resolve/simple-err))
    (finish (promise:add-work explicit-resolve/explicit-resolve))
    (finish (promise:add-work explicit-resolve/reject-err))
    (finish (promise:add-work explicit-resolve/reject-non-err))

    (finish (promise:add-work reject/simple))
    (finish (promise:add-work reject/simple-err))
    (finish (promise:add-work reject/explicit-resolve))
    (finish (promise:add-work reject/reject-err))
    (finish (promise:add-work reject/reject-non-err))

    (sleep 0.1)

    ;; test for simple/* combination
    (is-values (tpool:get-result simple/simple) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status simple/simple))
    (is eq t   (promise:promise-finished-p simple/simple))
    (is eq t   (promise:promise-resolved-p simple/simple))
    (is eq nil (promise:promise-rejected-p simple/simple))
    (is eq nil (promise:promise-errored-p  simple/simple))
    (is eq nil (promise:promise-error-obj  simple/simple))

    (is-values (tpool:get-result simple/simple-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status simple/simple-err))
    (is eq nil (promise:promise-finished-p simple/simple-err))
    (is eq nil (promise:promise-resolved-p simple/simple-err))
    (is eq t   (promise:promise-rejected-p simple/simple-err))
    (is eq t   (promise:promise-errored-p  simple/simple-err))
    (of-type error (promise:promise-error-obj simple/simple-err))

    (is-values (tpool:get-result simple/explicit-resolve) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status simple/explicit-resolve))
    (is eq t   (promise:promise-finished-p simple/explicit-resolve))
    (is eq t   (promise:promise-resolved-p simple/explicit-resolve))
    (is eq nil (promise:promise-rejected-p simple/explicit-resolve))
    (is eq nil (promise:promise-errored-p  simple/explicit-resolve))
    (is eq nil (promise:promise-error-obj  simple/explicit-resolve))

    (is-values (tpool:get-result simple/reject-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status simple/reject-err))
    (is eq nil (promise:promise-finished-p simple/reject-err))
    (is eq nil (promise:promise-resolved-p simple/reject-err))
    (is eq t   (promise:promise-rejected-p simple/reject-err))
    (is eq t   (promise:promise-errored-p  simple/reject-err))
    (of-type error (promise:promise-error-obj simple/reject-err))

    (is-values (tpool:get-result simple/reject-non-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status simple/reject-non-err))
    (is eq nil (promise:promise-finished-p simple/reject-non-err))
    (is eq nil (promise:promise-resolved-p simple/reject-non-err))
    (is eq t   (promise:promise-rejected-p simple/reject-non-err))
    (is eq t   (promise:promise-errored-p  simple/reject-non-err))
    (of-type error (promise:promise-error-obj simple/reject-non-err))
    ;; -------

    ;; test for explicit-resolve/* combination
    (is-values (tpool:get-result explicit-resolve/simple) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status explicit-resolve/simple))
    (is eq t   (promise:promise-finished-p explicit-resolve/simple))
    (is eq t   (promise:promise-resolved-p explicit-resolve/simple))
    (is eq nil (promise:promise-rejected-p explicit-resolve/simple))
    (is eq nil (promise:promise-errored-p  explicit-resolve/simple))
    (is eq nil (promise:promise-error-obj  explicit-resolve/simple))

    (is-values (tpool:get-result explicit-resolve/simple-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status explicit-resolve/simple-err))
    (is eq nil (promise:promise-finished-p explicit-resolve/simple-err))
    (is eq nil (promise:promise-resolved-p explicit-resolve/simple-err))
    (is eq t   (promise:promise-rejected-p explicit-resolve/simple-err))
    (is eq t   (promise:promise-errored-p  explicit-resolve/simple-err))
    (of-type error (promise:promise-error-obj explicit-resolve/simple-err))

    (is-values (tpool:get-result explicit-resolve/explicit-resolve) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status explicit-resolve/explicit-resolve))
    (is eq t   (promise:promise-finished-p explicit-resolve/explicit-resolve))
    (is eq t   (promise:promise-resolved-p explicit-resolve/explicit-resolve))
    (is eq nil (promise:promise-rejected-p explicit-resolve/explicit-resolve))
    (is eq nil (promise:promise-errored-p  explicit-resolve/explicit-resolve))
    (is eq nil (promise:promise-error-obj  explicit-resolve/explicit-resolve))

    (is-values (tpool:get-result explicit-resolve/reject-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status explicit-resolve/reject-err))
    (is eq nil (promise:promise-finished-p explicit-resolve/reject-err))
    (is eq nil (promise:promise-resolved-p explicit-resolve/reject-err))
    (is eq t   (promise:promise-rejected-p explicit-resolve/reject-err))
    (is eq t   (promise:promise-errored-p  explicit-resolve/reject-err))
    (of-type error (promise:promise-error-obj explicit-resolve/reject-err))

    (is-values (tpool:get-result explicit-resolve/reject-non-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status explicit-resolve/reject-non-err))
    (is eq nil (promise:promise-finished-p explicit-resolve/reject-non-err))
    (is eq nil (promise:promise-resolved-p explicit-resolve/reject-non-err))
    (is eq t   (promise:promise-rejected-p explicit-resolve/reject-non-err))
    (is eq t   (promise:promise-errored-p  explicit-resolve/reject-non-err))
    (of-type error (promise:promise-error-obj explicit-resolve/reject-non-err))
    ;; -------

    ;; test for reject/* combination
    (is-values (tpool:get-result reject/simple) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status reject/simple))
    (is eq nil      (promise:promise-finished-p reject/simple))
    (is eq nil      (promise:promise-resolved-p reject/simple))
    (is eq t        (promise:promise-rejected-p reject/simple))
    (is eq t        (promise:promise-errored-p  reject/simple))
    (of-type error  (promise:promise-error-obj  reject/simple))

    (is-values (tpool:get-result reject/simple-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status reject/simple-err))
    (is eq nil      (promise:promise-finished-p reject/simple-err))
    (is eq nil      (promise:promise-resolved-p reject/simple-err))
    (is eq t        (promise:promise-rejected-p reject/simple-err))
    (is eq t        (promise:promise-errored-p  reject/simple-err))
    (of-type error  (promise:promise-error-obj  reject/simple-err))

    (is-values (tpool:get-result reject/explicit-resolve) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status reject/explicit-resolve))
    (is eq nil      (promise:promise-finished-p reject/explicit-resolve))
    (is eq nil      (promise:promise-resolved-p reject/explicit-resolve))
    (is eq t        (promise:promise-rejected-p reject/explicit-resolve))
    (is eq t        (promise:promise-errored-p  reject/explicit-resolve))
    (of-type error  (promise:promise-error-obj  reject/explicit-resolve))

    (is-values (tpool:get-result reject/reject-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status reject/reject-err))
    (is eq nil      (promise:promise-finished-p reject/reject-err))
    (is eq nil      (promise:promise-resolved-p reject/reject-err))
    (is eq t        (promise:promise-rejected-p reject/reject-err))
    (is eq t        (promise:promise-errored-p  reject/reject-err))
    (of-type error  (promise:promise-error-obj  reject/reject-err))

    (is-values (tpool:get-result reject/reject-non-err) (eql nil) (eql nil))
    (is eq :errored (tpool:get-status reject/reject-non-err))
    (is eq nil      (promise:promise-finished-p reject/reject-non-err))
    (is eq nil      (promise:promise-resolved-p reject/reject-non-err))
    (is eq t        (promise:promise-rejected-p reject/reject-non-err))
    (is eq t        (promise:promise-errored-p  reject/reject-non-err))
    (of-type error  (promise:promise-error-obj  reject/reject-non-err))
    ))

(define-test promisify-fn :parent promise
  (let ((promise1 (promise:promisify-fn #'(lambda () 6)))
        (promise2 (promise:promisify-fn #'(lambda () (+ 1 2 3))))
        (promise3 (promise:promisify-fn #'(lambda () (/ 1 (gen-0)))))
        (promise4 (promise:promisify-fn #'(lambda () (funcall #'basic-promise-gen :simple))))
        (promise5 (promise:promisify-fn #'(lambda () (funcall #'basic-promise-gen :simple-err)))))
    (sleep 0.1)

    (is eq t (promise:promisep promise1))
    (is-values (tpool:get-result promise1) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status promise1))
    (is eq t   (promise:promise-finished-p promise1))
    (is eq t   (promise:promise-resolved-p promise1))
    (is eq nil (promise:promise-rejected-p promise1))
    (is eq nil (promise:promise-errored-p  promise1))
    (is eq nil (promise:promise-error-obj  promise1))

    (is eq t (promise:promisep promise2))
    (is-values (tpool:get-result promise2) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status promise2))
    (is eq t   (promise:promise-finished-p promise2))
    (is eq t   (promise:promise-resolved-p promise2))
    (is eq nil (promise:promise-rejected-p promise2))
    (is eq nil (promise:promise-errored-p  promise2))
    (is eq nil (promise:promise-error-obj  promise2))

    (is eq t        (promise:promisep promise3))
    (is-values      (tpool:get-result promise3) (eq nil) (eq nil))
    (is eq :errored (tpool:get-status promise3))
    (is eq nil      (promise:promise-finished-p promise3))
    (is eq nil      (promise:promise-resolved-p promise3))
    (is eq t        (promise:promise-rejected-p promise3))
    (is eq t        (promise:promise-errored-p  promise3))
    (of-type error  (promise:promise-error-obj  promise3))

    (is eq t (promise:promisep promise4))
    (is-values (tpool:get-result promise4) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status promise4))
    (is eq t   (promise:promise-finished-p promise4))
    (is eq t   (promise:promise-resolved-p promise4))
    (is eq nil (promise:promise-rejected-p promise4))
    (is eq nil (promise:promise-errored-p  promise4))
    (is eq nil (promise:promise-error-obj  promise4))

    (is eq t        (promise:promisep promise5))
    (is-values      (tpool:get-result promise5) (eq nil) (eq nil))
    (is eq :errored (tpool:get-status promise5))
    (is eq nil      (promise:promise-finished-p promise5))
    (is eq nil      (promise:promise-resolved-p promise5))
    (is eq t        (promise:promise-rejected-p promise5))
    (is eq t        (promise:promise-errored-p  promise5))
    (of-type error  (promise:promise-error-obj  promise5))))

(define-test promisify-form :parent promise
  (let ((promise1 (promise:promisify-form 6))
        (promise2 (promise:promisify-form (+ 1 2 3)))
        (promise3 (promise:promisify-form (/ 1 (gen-0))))
        (promise4 (promise:promisify-form (funcall #'basic-promise-gen :simple)))
        (promise5 (promise:promisify-form (funcall #'basic-promise-gen :simple-err))))
    (sleep 0.1)

    (is eq t (promise:promisep promise1))
    (is-values (tpool:get-result promise1) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status promise1))
    (is eq t   (promise:promise-finished-p promise1))
    (is eq t   (promise:promise-resolved-p promise1))
    (is eq nil (promise:promise-rejected-p promise1))
    (is eq nil (promise:promise-errored-p  promise1))
    (is eq nil (promise:promise-error-obj  promise1))

    (is eq t (promise:promisep promise2))
    (is-values (tpool:get-result promise2) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status promise2))
    (is eq t   (promise:promise-finished-p promise2))
    (is eq t   (promise:promise-resolved-p promise2))
    (is eq nil (promise:promise-rejected-p promise2))
    (is eq nil (promise:promise-errored-p  promise2))
    (is eq nil (promise:promise-error-obj  promise2))

    (is eq t        (promise:promisep promise3))
    (is-values      (tpool:get-result promise3) (eq nil) (eq nil))
    (is eq :errored (tpool:get-status promise3))
    (is eq nil      (promise:promise-finished-p promise3))
    (is eq nil      (promise:promise-resolved-p promise3))
    (is eq t        (promise:promise-rejected-p promise3))
    (is eq t        (promise:promise-errored-p  promise3))
    (of-type error  (promise:promise-error-obj  promise3))

    (is eq t (promise:promisep promise4))
    (is-values (tpool:get-result promise4) (equal (list 6)) (eq t))
    (is eq :finished (tpool:get-status promise4))
    (is eq t   (promise:promise-finished-p promise4))
    (is eq t   (promise:promise-resolved-p promise4))
    (is eq nil (promise:promise-rejected-p promise4))
    (is eq nil (promise:promise-errored-p  promise4))
    (is eq nil (promise:promise-error-obj  promise4))

    (is eq t        (promise:promisep promise5))
    (is-values      (tpool:get-result promise5) (eq nil) (eq nil))
    (is eq :errored (tpool:get-status promise5))
    (is eq nil      (promise:promise-finished-p promise5))
    (is eq nil      (promise:promise-resolved-p promise5))
    (is eq t        (promise:promise-rejected-p promise5))
    (is eq t        (promise:promise-errored-p  promise5))
    (of-type error  (promise:promise-error-obj  promise5))))

(define-test depth-forward :parent :promise
  (dotimes (i 10)
    (let* ((depth (random 10))
           (promise1 (nested-promise-gen depth :simple)) ; simple, simple-err, explicit-resolve, reject-err, reject-non-err
           (promise2 (nested-promise-gen depth :simple-err))
           (promise3 (nested-promise-gen depth :explicit-resolve))
           (promise4 (nested-promise-gen depth :reject-err))
           (promise5 (nested-promise-gen depth :reject-non-err)))
      (true (promise:promisep promise1))
      (true (promise:promisep promise2))
      (true (promise:promisep promise3))
      (true (promise:promisep promise4))
      (true (promise:promisep promise5))

      (finish (promise:add-work promise1))
      (finish (promise:add-work promise2))
      (finish (promise:add-work promise3))
      (finish (promise:add-work promise4))
      (finish (promise:add-work promise5))

      (sleep 0.1)

      (is-values (tpool:get-result promise1) (equal (list 6)) (eq t))
      (is eq :finished (tpool:get-status promise1))
      (is eq t   (promise:promise-finished-p promise1))
      (is eq t   (promise:promise-resolved-p promise1))
      (is eq nil (promise:promise-rejected-p promise1))
      (is eq nil (promise:promise-errored-p  promise1))
      (is eq nil (promise:promise-error-obj  promise1))

      (is-values      (tpool:get-result promise2) (eq nil) (eq nil))
      (is eq :errored (tpool:get-status promise2))
      (is eq nil      (promise:promise-finished-p promise2))
      (is eq nil      (promise:promise-resolved-p promise2))
      (is eq t        (promise:promise-rejected-p promise2))
      (is eq t        (promise:promise-errored-p  promise2))
      (of-type error  (promise:promise-error-obj  promise2))

      (is-values (tpool:get-result promise3) (equal (list 6)) (eq t))
      (is eq :finished (tpool:get-status promise3))
      (is eq t   (promise:promise-finished-p promise3))
      (is eq t   (promise:promise-resolved-p promise3))
      (is eq nil (promise:promise-rejected-p promise3))
      (is eq nil (promise:promise-errored-p  promise3))
      (is eq nil (promise:promise-error-obj  promise3))

      (is-values      (tpool:get-result promise4) (eq nil) (eq nil))
      (is eq :errored (tpool:get-status promise4))
      (is eq nil      (promise:promise-finished-p promise4))
      (is eq nil      (promise:promise-resolved-p promise4))
      (is eq t        (promise:promise-rejected-p promise4))
      (is eq t        (promise:promise-errored-p  promise4))
      (of-type error  (promise:promise-error-obj  promise4))

      (is-values      (tpool:get-result promise5) (eq nil) (eq nil))
      (is eq :errored (tpool:get-status promise5))
      (is eq nil      (promise:promise-finished-p promise5))
      (is eq nil      (promise:promise-resolved-p promise5))
      (is eq t        (promise:promise-rejected-p promise5))
      (is eq t        (promise:promise-errored-p  promise5))
      (of-type error  (promise:promise-error-obj  promise5))
      )))
